package cn.middle.remote.handler.netty;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandler;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.internal.TypeParameterMatcher;
/**
 * extends ChannelInboundHandlerAdapter
 * @author r
 *     
 * @param <I>
 */
public abstract class BaseHandler<I> extends ChannelInboundHandlerAdapter 
{

	
	
	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
	}

	
	private final TypeParameterMatcher matcher;
	private final boolean autoRelease;

	/**
	 * see {@link #BaseHandler(boolean)} with {@code true} as
	 * boolean parameter.
	 */
	protected BaseHandler() {
		this(true);
	}

	/**
	 * Create a new instance which will try to detect the types to match out of the
	 * type parameter of the class.
	 *
	 * @param autoRelease {@code true} if handled messages should be released
	 *                    automatically by passing them to
	 *                    {@link ReferenceCountUtil#release(Object)}.
	 */
	protected BaseHandler(boolean autoRelease) {
		matcher = TypeParameterMatcher.find(this, BaseHandler.class, "I");
		this.autoRelease = autoRelease;
	}

	/**
	 * see {@link #BaseHandler(Class, boolean)} with {@code true} as
	 * boolean value.
	 */
	protected BaseHandler(Class<? extends I> inboundMessageType) {
		this(inboundMessageType, true);
	}

	/**
	 * Create a new instance
	 *
	 * @param inboundMessageType The type of messages to match
	 * @param autoRelease        {@code true} if handled messages should be released
	 *                           automatically by passing them to
	 *                           {@link ReferenceCountUtil#release(Object)}.
	 */
	protected BaseHandler(Class<? extends I> inboundMessageType, boolean autoRelease) {
		matcher = TypeParameterMatcher.get(inboundMessageType);
		this.autoRelease = autoRelease;
	}

	/**
	 * Returns {@code true} if the given message should be handled. If {@code false}
	 * it will be passed to the next {@link ChannelInboundHandler} in the
	 * {@link ChannelPipeline}.
	 */
	public boolean acceptInboundMessage(Object msg) throws Exception {
		return matcher.match(msg);
	}

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		boolean release = true;
		try {
			if (acceptInboundMessage(msg)) {
				@SuppressWarnings("unchecked")
				I imsg = (I) msg;
				channelRead0(ctx, imsg);
			} else {
				release = false;
				ctx.fireChannelRead(msg);
			}
		} finally {
			if (autoRelease && release) {
				ReferenceCountUtil.release(msg);
			}
		}
	}

	/**
	 * <strong>Please keep in mind that this method will be renamed to
	 * {@code messageReceived(ChannelHandlerContext, I)} in 5.0.</strong>
	 *
	 * Is called for each message of type {@link I}.
	 *
	 * @param ctx the {@link ChannelHandlerContext} which this
	 *            {@link BaseHandler} belongs to
	 * @param msg the message to handle
	 * @throws Exception is thrown if an error occurred
	 */
	protected abstract void channelRead0(ChannelHandlerContext ctx, I msg) throws Exception;

	
}

